/** @file
 *  @brief HoG Service sample
 */

/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/types.h>
#include <zephyr/drivers/gpio.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>

#include "hog.h"
#include "../../subsys/bluetooth/host/keys.h"
#include "../../subsys//bluetooth/host/id.h"
#include "../../include/zephyr/bluetooth/addr.h"


#include <zephyr/kernel.h>
#include <zephyr/device.h>


static uint8_t simulate_input;
static uint8_t ctrl_point;

static struct bt_conn *hids_conn;
static struct k_timer hids_timer;

static enum bthid_state ble_state;
static enum bthid_state state_pending;

static struct k_work hog_button;
static struct k_work_delayable state_work;
static struct k_work_delayable bas_work;
static K_SEM_DEFINE(state_sem, 1, 1);

static void ble_ready(void);
static void bt_keys_clear_all(void);
static void ble_advertise(bool reconnect);
static void le_conn_connected(struct bt_conn *conn, uint8_t err);
static void le_conn_disconnected(struct bt_conn *conn, uint8_t reason);
static void le_conn_security_changed(struct bt_conn *conn, bt_security_t level, uint8_t err);
static void ble_set_state_async(enum bthid_state state, uint16_t delay);
static void hog_button_loop(struct k_work *work);
static void ble_state_handler(struct k_work *work);
static void ble_leava_state(enum bthid_state new);
static void ble_enter_state(enum bthid_state old);
static void ble_set_state(enum bthid_state state);
static enum bthid_state ble_get_state(void);


struct generic_data {
	uint32_t size;
	const void *data;
};
#define GENERIC_STR(str)   (void *)(&(const struct generic_data) { .size = sizeof(str) - 1, .data = str})
#define GENERIC_DATA(dat)  (void *)(&(const struct generic_data) { .size = sizeof(dat), .data = &(dat)})
#define GENERIC_ARRAY(...) (void *)(&(const struct generic_data) { .size = sizeof((const uint8_t []){__VA_ARGS__}), .data = (const uint8_t[]) { __VA_ARGS__ }})
#define GENERIC_VERSION(n) GENERIC_ARRAY('V', 0x30 + (n / 100), '.', 0x30 + n / 10 % 10, '.', 0x30 + n % 10)
#define LE16(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)


enum {
	HIDS_REMOTE_WAKE = BIT(0),
	HIDS_NORMALLY_CONNECTABLE = BIT(1),
};

struct hids_info {
	uint16_t version; /* version number of base USB HID Specification */
	uint8_t code; /* country HID Device hardware is localized for. */
	uint8_t flags;
} __packed;

struct hids_report {
	uint8_t id; /* report id */
	uint8_t type; /* report type */
} __packed;

static struct hids_info info = {
	.version = 0x0000,
	.code = 0x00,
	.flags = HIDS_NORMALLY_CONNECTABLE,
};

enum {
	HIDS_INPUT = 0x01,
	HIDS_OUTPUT = 0x02,
	HIDS_FEATURE = 0x03,
};

static struct hids_report input = {
	.id = 0x01,
	.type = HIDS_INPUT,
};

static struct bt_conn_cb conn_callbacks = {
	.connected = le_conn_connected,
	.disconnected = le_conn_disconnected,
	.security_changed = le_conn_security_changed,
};


static const uint8_t report_map[] = {
	0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
	0x09, 0x05,        // Usage (Game Pad)
	0xA1, 0x01,        // Collection (Application)
	0x85, 0x01,        //   Report ID (1)
	0x09, 0x01,        //   Usage (Pointer)
	0xA1, 0x00,        //   Collection (Physical)
	0x09, 0x30,        //     Usage (X)
	0x09, 0x31,        //     Usage (Y)
	0x15, 0x00,        //     Logical Minimum (0)
	0x27, 0xFF, 0xFF, 0x00, 0x00,  //     Logical Maximum (65534)
	0x95, 0x02,        //     Report Count (2)
	0x75, 0x10,        //     Report Size (16)
	0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0xC0,              //   End Collection
	0x09, 0x01,        //   Usage (Pointer)
	0xA1, 0x00,        //   Collection (Physical)
	0x09, 0x32,        //     Usage (Z)
	0x09, 0x35,        //     Usage (Rz)
	0x15, 0x00,        //     Logical Minimum (0)
	0x27, 0xFF, 0xFF, 0x00, 0x00,  //     Logical Maximum (65534)
	0x95, 0x02,        //     Report Count (2)
	0x75, 0x10,        //     Report Size (16)
	0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0xC0,              //   End Collection
	0x05, 0x02,        //   Usage Page (Sim Ctrls)
	0x09, 0xC5,        //   Usage (Brake)
	0x15, 0x00,        //   Logical Minimum (0)
	0x26, 0xFF, 0x03,  //   Logical Maximum (1023)
	0x95, 0x01,        //   Report Count (1)
	0x75, 0x0A,        //   Report Size (10)
	0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x15, 0x00,        //   Logical Minimum (0)
	0x25, 0x00,        //   Logical Maximum (0)
	0x75, 0x06,        //   Report Size (6)
	0x95, 0x01,        //   Report Count (1)
	0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x05, 0x02,        //   Usage Page (Sim Ctrls)
	0x09, 0xC4,        //   Usage (Accelerator)
	0x15, 0x00,        //   Logical Minimum (0)
	0x26, 0xFF, 0x03,  //   Logical Maximum (1023)
	0x95, 0x01,        //   Report Count (1)
	0x75, 0x0A,        //   Report Size (10)
	0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x15, 0x00,        //   Logical Minimum (0)
	0x25, 0x00,        //   Logical Maximum (0)
	0x75, 0x06,        //   Report Size (6)
	0x95, 0x01,        //   Report Count (1)
	0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
	0x09, 0x39,        //   Usage (Hat switch)
	0x15, 0x01,        //   Logical Minimum (1)
	0x25, 0x08,        //   Logical Maximum (8)
	0x35, 0x00,        //   Physical Minimum (0)
	0x46, 0x3B, 0x01,  //   Physical Maximum (315)
	0x66, 0x14, 0x00,  //   Unit (System: English Rotation, Length: Centimeter)
	0x75, 0x04,        //   Report Size (4)
	0x95, 0x01,        //   Report Count (1)
	0x81, 0x42,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
	0x75, 0x04,        //   Report Size (4)
	0x95, 0x01,        //   Report Count (1)
	0x15, 0x00,        //   Logical Minimum (0)
	0x25, 0x00,        //   Logical Maximum (0)
	0x35, 0x00,        //   Physical Minimum (0)
	0x45, 0x00,        //   Physical Maximum (0)
	0x65, 0x00,        //   Unit (None)
	0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x05, 0x09,        //   Usage Page (Button)
	0x19, 0x01,        //   Usage Minimum (0x01)
	0x29, 0x0F,        //   Usage Maximum (0x0F)
	0x15, 0x00,        //   Logical Minimum (0)
	0x25, 0x01,        //   Logical Maximum (1)
	0x75, 0x01,        //   Report Size (1)
	0x95, 0x0F,        //   Report Count (15)
	0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x15, 0x00,        //   Logical Minimum (0)
	0x25, 0x00,        //   Logical Maximum (0)
	0x75, 0x01,        //   Report Size (1)
	0x95, 0x01,        //   Report Count (1)
	0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x05, 0x0C,        //   Usage Page (Consumer)
	0x0A, 0xB2, 0x00,  //   Usage (Record)
	0x15, 0x00,        //   Logical Minimum (0)
	0x25, 0x01,        //   Logical Maximum (1)
	0x95, 0x01,        //   Report Count (1)
	0x75, 0x01,        //   Report Size (1)
	0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x15, 0x00,        //   Logical Minimum (0)
	0x25, 0x00,        //   Logical Maximum (0)
	0x75, 0x07,        //   Report Size (7)
	0x95, 0x01,        //   Report Count (1)
	0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
	0x05, 0x0F,        //   Usage Page (PID Page)
	0x09, 0x21,        //   Usage (0x21)
	0x85, 0x03,        //   Report ID (3)
	0xA1, 0x02,        //   Collection (Logical)
	0x09, 0x97,        //     Usage (0x97)
	0x15, 0x00,        //     Logical Minimum (0)
	0x25, 0x01,        //     Logical Maximum (1)
	0x75, 0x04,        //     Report Size (4)
	0x95, 0x01,        //     Report Count (1)
	0x91, 0x02,        //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
	0x15, 0x00,        //     Logical Minimum (0)
	0x25, 0x00,        //     Logical Maximum (0)
	0x75, 0x04,        //     Report Size (4)
	0x95, 0x01,        //     Report Count (1)
	0x91, 0x03,        //     Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
	0x09, 0x70,        //     Usage (0x70)
	0x15, 0x00,        //     Logical Minimum (0)
	0x25, 0x64,        //     Logical Maximum (100)
	0x75, 0x08,        //     Report Size (8)
	0x95, 0x04,        //     Report Count (4)
	0x91, 0x02,        //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
	0x09, 0x50,        //     Usage (0x50)
	0x66, 0x01, 0x10,  //     Unit (System: SI Linear, Time: Seconds)
	0x55, 0x0E,        //     Unit Exponent (-2)
	0x15, 0x00,        //     Logical Minimum (0)
	0x26, 0xFF, 0x00,  //     Logical Maximum (255)
	0x75, 0x08,        //     Report Size (8)
	0x95, 0x01,        //     Report Count (1)
	0x91, 0x02,        //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
	0x09, 0xA7,        //     Usage (0xA7)
	0x15, 0x00,        //     Logical Minimum (0)
	0x26, 0xFF, 0x00,  //     Logical Maximum (255)
	0x75, 0x08,        //     Report Size (8)
	0x95, 0x01,        //     Report Count (1)
	0x91, 0x02,        //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
	0x65, 0x00,        //     Unit (None)
	0x55, 0x00,        //     Unit Exponent (0)
	0x09, 0x7C,        //     Usage (0x7C)
	0x15, 0x00,        //     Logical Minimum (0)
	0x26, 0xFF, 0x00,  //     Logical Maximum (255)
	0x75, 0x08,        //     Report Size (8)
	0x95, 0x01,        //     Report Count (1)
	0x91, 0x02,        //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
	0xC0,              //   End Collection
	0xC0,              // End Collection

	// 283 bytes
};


static ssize_t read_info(struct bt_conn *conn,
			  const struct bt_gatt_attr *attr, void *buf,
			  uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
				 sizeof(struct hids_info));
}

static ssize_t generic_read(struct bt_conn *conn,
			     const struct bt_gatt_attr *attr, void *buf,
			     uint16_t len, uint16_t offset)
{
	struct generic_data *info = attr->user_data;
	return bt_gatt_attr_read(conn, attr, buf, len, offset, info->data, info->size);
}

static ssize_t read_report_map(struct bt_conn *conn,
			       const struct bt_gatt_attr *attr, void *buf,
			       uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, report_map,
				 sizeof(report_map));
}

static ssize_t read_report(struct bt_conn *conn,
			   const struct bt_gatt_attr *attr, void *buf,
			   uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
				 sizeof(struct hids_report));
}

static void input_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
	simulate_input = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0;
}

static ssize_t read_input_report(struct bt_conn *conn,
				 const struct bt_gatt_attr *attr, void *buf,
				 uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, NULL, 0);
}

static ssize_t write_ctrl_point(struct bt_conn *conn,
				const struct bt_gatt_attr *attr,
				const void *buf, uint16_t len, uint16_t offset,
				uint8_t flags)
{
	uint8_t *value = attr->user_data;

	if (offset + len > sizeof(ctrl_point)) {
		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
	}

	memcpy(value + offset, buf, len);

	return len;
}

#if CONFIG_SAMPLE_BT_USE_AUTHENTICATION
/* Require encryption using authenticated link-key. */
#define SAMPLE_BT_PERM_READ BT_GATT_PERM_READ_AUTHEN
#define SAMPLE_BT_PERM_WRITE BT_GATT_PERM_WRITE_AUTHEN
#else
/* Require encryption. */
#define SAMPLE_BT_PERM_READ BT_GATT_PERM_READ_ENCRYPT
#define SAMPLE_BT_PERM_WRITE BT_GATT_PERM_WRITE_ENCRYPT
#endif

/******************* bas ********************/
static uint8_t battery_level;

static void blvl_ccc_cfg_changed(const struct bt_gatt_attr *attr,
				       uint16_t value)
{
	ARG_UNUSED(attr);

	bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);

	printk("BAS Notifications %s\n", notif_enabled ? "enabled" : "disabled");
}

static ssize_t read_blvl(struct bt_conn *conn,
			       const struct bt_gatt_attr *attr, void *buf,
			       uint16_t len, uint16_t offset)
{
	uint8_t lvl8 = battery_level;

	return bt_gatt_attr_read(conn, attr, buf, len, offset, &lvl8,
				 sizeof(lvl8));
}

static const struct bt_gatt_cpf level_cpf = {
	.format = 0x04,        /* uint8 */
	.exponent = 0x0,
	.unit = 0x27AD,        /* Percentage */
	.name_space = 0x01,    /* Bluetooth SIG */
	.description = 0x0106, /* "main" */
};

struct dis_pnp {
	uint8_t pnp_vid_src;
	uint16_t pnp_vid;
	uint16_t pnp_pid;
	uint16_t pnp_ver;
} __packed;

static struct dis_pnp dis_pnp_id = {
	.pnp_vid_src = CONFIG_BT_DIS_PNP_VID_SRC,
	.pnp_vid = CONFIG_BT_DIS_PNP_VID,
	.pnp_pid = CONFIG_BT_DIS_PNP_PID,
	.pnp_ver = CONFIG_BT_DIS_PNP_VER,
};

static ssize_t read_str(struct bt_conn *conn,
			  const struct bt_gatt_attr *attr, void *buf,
			  uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
				 strlen(attr->user_data));
}

static ssize_t read_pnp_id(struct bt_conn *conn,
			   const struct bt_gatt_attr *attr, void *buf,
			   uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, &dis_pnp_id,
				 sizeof(dis_pnp_id));
}
/* HID Service Declaration */
BT_GATT_SERVICE_DEFINE(hog_svc,
	BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS),								// one uuid
	BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, BT_GATT_CHRC_READ,  		//two uuid 
			       BT_GATT_PERM_READ, read_info, NULL, &info),
	BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, BT_GATT_CHRC_READ, 	//two uuid 
			       BT_GATT_PERM_READ, read_report_map, NULL, NULL),
	BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT,							//two uuid 
			       BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
			       SAMPLE_BT_PERM_READ,
			       read_input_report, NULL, NULL),
	BT_GATT_CCC(input_ccc_changed,						//0x2902 one uuid
		    SAMPLE_BT_PERM_READ | SAMPLE_BT_PERM_WRITE),
	BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ,	//one uuid
			   read_report, NULL, &input),
	
	BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT,		//two uuid
			       BT_GATT_CHRC_WRITE_WITHOUT_RESP,
			       BT_GATT_PERM_WRITE,
			       NULL, write_ctrl_point, &ctrl_point),


	BT_GATT_PRIMARY_SERVICE(BT_UUID_DIS),		//one uuid
	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MODEL_NUMBER,		//two uuid 
			       BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
			       read_str, NULL, CONFIG_BT_DIS_MODEL),
	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MANUFACTURER_NAME,	//two uuid 
			       BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
			       read_str, NULL, CONFIG_BT_DIS_MANUF),

	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_PNP_ID,				//two uuid 
			       BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
			       read_pnp_id, NULL, &dis_pnp_id),

	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SERIAL_NUMBER,		//two uuid 
			       BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
			       read_str, NULL,
			       CONFIG_BT_DIS_SERIAL_NUMBER_STR),
	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_FIRMWARE_REVISION,	//two uuid 
			       BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
			       read_str, NULL, CONFIG_BT_DIS_FW_REV_STR),
	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_HARDWARE_REVISION,	//two uuid 
			       BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
			       read_str, NULL, CONFIG_BT_DIS_HW_REV_STR),
	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SOFTWARE_REVISION,		//two uuid 
			       BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
			       read_str, NULL, CONFIG_BT_DIS_SW_REV_STR),

	BT_GATT_PRIMARY_SERVICE(BT_UUID_BAS),		//one uuid
	BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL,			//two uuid 
				BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
				BT_GATT_PERM_READ, read_blvl, NULL,
				&battery_level),
	BT_GATT_CCC(blvl_ccc_cfg_changed,					//one uuid
			BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
	BT_GATT_CPF(&level_cpf),


	BT_GATT_PRIMARY_SERVICE(BT_UUID_GAP),
	BT_GATT_CHARACTERISTIC(BT_UUID_GAP_DEVICE_NAME, BT_GATT_CHRC_READ,
			       BT_GATT_PERM_READ, read_info, NULL, CONFIG_BT_DEVICE_NAME),
	BT_GATT_CHARACTERISTIC(BT_UUID_GAP_APPEARANCE, BT_GATT_CHRC_READ,
			       BT_GATT_PERM_READ, generic_read, NULL, GENERIC_ARRAY(LE16(964))), /*LE16(964) = ESP_BLE_APPEARANCE_HID_GAMEPAD  0x03C4*/

);

/***********************************************************************************************************************************************/
/*******************************************************************************/

static void ble_keys_clear(struct bt_keys *keys, void *data)
{
	uint8_t unused = 0;
	data = &unused;
	bt_keys_clear(keys);
}

static void bt_keys_clear_all(void )
{
	bt_keys_foreach_type(BT_KEYS_ALL, ble_keys_clear, NULL);
}

static const struct bt_data ble_ad_discov[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA_BYTES(BT_DATA_UUID16_SOME, 0x12, 0x18),
	BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, 0xc4, 0x03),
};


static void add_bonded_addr_to_filter_list(struct bt_keys *keys, void *data)
{
	char filterbuf[50];
	if(keys->addr.type == BT_ADDR_LE_RANDOM)//随机的设备地址
	{
		keys_add_id(keys, data);//添加可解析的私有地址
		bt_addr_le_to_str(&keys->addr, filterbuf, sizeof(filterbuf));
		printk("keys -> address : %s", filterbuf);
	}
	bt_le_filter_accept_list_add(&(keys->addr));
}
static void ble_advertise(bool reconnect)//重新连接
{
	int err;
	size_t ad_len, scan_rsp_len;
	// bt_addr_le_t peer_addr;
	const struct bt_data *ad, *scan_rsp;
	struct bt_keys *peer_key;
	struct bt_le_adv_param param = {
		.peer = NULL,
		.interval_min = BT_GAP_ADV_FAST_INT_MIN_2,
		.interval_max = BT_GAP_ADV_FAST_INT_MAX_2,
		.options = BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME
	};
	//BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME

	char adverbuf[50];

	if (reconnect && false) {
		bt_keys_foreach_type(BT_KEYS_ALL, add_bonded_addr_to_filter_list, NULL);

		// if (!bt_keys_upper_addr(&peer_addr))  
		// {
		// 	param.peer = &peer_addr;
		// }
		peer_key = bt_keys_get_last_keys_updated();
		if(peer_key)
		{
			param.peer =(bt_addr_le_t *) (&(peer_key->addr));
		}
		bt_addr_le_to_str(&peer_key->addr, adverbuf, sizeof(adverbuf));
		addr_res_enable(true);
		printk("reconnect = false, adverbuf: %s\n", adverbuf);

	}

	scan_rsp = NULL; //ble_ad_discov;
	scan_rsp_len = 0; //ARRAY_SIZE(ble_ad_discov);

	ad = ble_ad_discov;
	ad_len = ARRAY_SIZE(ble_ad_discov);
	
	err = bt_le_adv_start(&param, ad, ad_len, scan_rsp, scan_rsp_len);
	if (err < 0) {
		printk("Failed to start advertising (err %d)\n", err);
	} else {
		printk("Advertising started\n");
	}
}

static void le_conn_connected(struct bt_conn *conn, uint8_t err)
{
	int rc;
	struct bt_conn_info info;
	rc = bt_conn_get_info(conn, &info);
	printk("le conn connected, err %d, rc %d, type %d\n", err, rc, info.type);

	if (rc || info.type != BT_CONN_TYPE_LE || err) {
		return;
	}

	char srcbuf[50];
	char dstbuf[50];
	char localbuf[50];
	char remotebuf[50];

	bt_addr_le_to_str(info.le.src, srcbuf, sizeof(srcbuf));
	bt_addr_le_to_str(info.le.dst, dstbuf, sizeof(dstbuf));
	bt_addr_le_to_str(info.le.local, localbuf, sizeof(localbuf));
	bt_addr_le_to_str(info.le.remote, remotebuf, sizeof(remotebuf));

	// time=0;
	printk("le conn info->addr src:%s \n", srcbuf);
	printk("le conn info->addr dst:%s \n", dstbuf);
	printk("le conn info->addr local:%s \n", localbuf);
	printk("le conn info->addr remote:%s \n", remotebuf);
	if (hids_conn == NULL) {
		hids_conn = bt_conn_ref(conn);
	}
}

static void le_conn_disconnected(struct bt_conn *conn, uint8_t reason)
{
	struct bt_conn_info info;
	int rc = bt_conn_get_info(conn, &info);

	if (rc || info.type != BT_CONN_TYPE_LE) {
		return;
	}

	printk("le conn disconnected %x\n", reason);
	if (hids_conn == conn) {
		bt_conn_unref(conn);
		simulate_input = 0;
		hids_conn = NULL;
	}
	bt_le_adv_stop();
	switch (ble_state) {
	case BTHID_STATE_DISCOVER:
		ble_advertise(false);
		printk("discon ble adv false\n");
		break;
	case BTHID_STATE_CONNECTING:
		ble_advertise(true);
		printk("discon ble adv true\n");
		break;
	case BTHID_STATE_ACTIVE:
		ble_set_state(BTHID_STATE_CONNECTING);
		printk("discon ble last ACTIVE -> CONNECTING\n");
		break;
	default: break;
	}
}

static void le_conn_security_changed(struct bt_conn *conn, bt_security_t level, uint8_t err)
{
	int rc;
	struct bt_conn_info info;

	printk("security level %d, err %d\n", level, err);
	if (err || (rc = bt_conn_get_info(conn, &info))
	    || info.type != BT_CONN_TYPE_LE
	    || conn != hids_conn) {
		return;
	}

	ble_set_state(BTHID_STATE_ACTIVE);
}
static void ble_ready(void)
{
	printk("ble_ready\n");
	bt_conn_cb_register(&conn_callbacks);
	ble_hid.set_state_async(BTHID_STATE_DISCOVER, 5000);	
}

static void ble_state_handler(struct k_work *work)
{
	enum bthid_state state;

	k_sem_take(&state_sem, K_FOREVER);
	state = state_pending;
	state_pending = BTHID_STATE_UNINIT;
	k_sem_give(&state_sem);

	if (state != BTHID_STATE_UNINIT) {
		ble_set_state(state);
	}
}

static void ble_set_state_async(enum bthid_state state,  uint16_t delay)
{
	k_sem_take(&state_sem, K_FOREVER);
	if (state_pending != BTHID_STATE_UNINIT) {
		printk("state %s, pending %s discarded\n",
			    bthid_state_string(state),  bthid_state_string(state_pending));
	}

	state_pending = state;
	k_sem_give(&state_sem);
	k_work_schedule(&state_work, K_MSEC(delay));//k_work_reschedule, k_work_schedule
	printk("k_work_schedule ok\n");
}

/***************************************************************************/

/***************************************************************************/

static void ble_leava_state(enum bthid_state new)
{
	switch (ble_state) {
	case BTHID_STATE_ACTIVE:
	case BTHID_STATE_CONNECTED:
		if (new < BTHID_STATE_CONNECTED && hids_conn) {
			bt_conn_disconnect(hids_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
		}

		if (new == BTHID_STATE_DISCOVER) {
			if (IS_ENABLED(CONFIG_BT_SMP)) { //断开已处于连接状态的设备连接到重新扫描发现设备模式时，清除所有保存的keys
				bt_keys_clear_all();
			}
		}
		break;

	case BTHID_STATE_DISCOVER:
	case BTHID_STATE_CONNECTING:
		if (hids_conn && new < BTHID_STATE_CONNECTED) {
			bt_conn_disconnect(hids_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);//远端蓝牙
		}
		// hostif_bt_le_adv_stop();	//停止当前的广播
		bt_le_adv_stop();

		// bt_le_addr_res_enable(false);
		addr_res_enable(false);  //CONFIG_BT_SMP

		// bl_le_res_list_clear();
		bt_hci_cmd_send_sync(BT_HCI_OP_LE_CLEAR_RL, NULL, NULL);
		bt_le_filter_accept_list_clear();
		break;

	default: break;
	}
}

static void ble_enter_state(enum bthid_state old)
{
	switch (ble_state) {
	case BTHID_STATE_READY:
		ble_ready();
		printk("enter_state -> BTHID_STATE_READY\n");
		break;

	case BTHID_STATE_POWER_OFF:
		printk("enter_state -> BTHID_STATE_POWER_OFF\n");
		break;
	
	case BTHID_STATE_POWER_ON:
		printk("enter_state -> BTHID_STATE_POWER_ON\n");
		ble_hid.set_state_async(BTHID_STATE_CONNECTING, (100));
		break;

	case BTHID_STATE_CONNECTING:
		ble_advertise(true);
		printk("enter_state -> BTHID_STATE_CONNECTING\n");
		break;

	case BTHID_STATE_DISCOVER:
		printk("enter_state -> BTHID_STATE_DISCOVER\n");
		if (old == BTHID_STATE_CONNECTED || old == BTHID_STATE_ACTIVE
		    || (old == BTHID_STATE_CONNECTING && hids_conn)) {
			break;
		}

		ble_advertise(false);
		break;

	case BTHID_STATE_ACTIVE: {
		printk("enter_state -> BTHID_STATE_ACTIVE\n");
		bt_le_adv_stop();
		k_timer_start(&hids_timer, K_MSEC(13), K_MSEC(13));
		break;
	}
	default: break;
	}
}

static void ble_set_state(enum bthid_state state)
{
	enum bthid_state old = ble_state;

	if (old == state || state >= BTHID_STATE_MAX) {
			printk("no change : %s -> %s\n",bthid_state_string(old), bthid_state_string(state) );
			return;
	}

	printk("%s -> %s \n", bthid_state_string(old), bthid_state_string(state));

	ble_leava_state(state);
	ble_state = state;
	ble_enter_state(old);
}

static enum bthid_state ble_get_state(void)
{
	return ble_state;
}

const struct bthid ble_hid = {
	.get_state = ble_get_state,
	.set_state = ble_set_state,
	.set_state_async = ble_set_state_async,
};
//////////////////////////////////////////////////////////////////////////////////

void hog_init(void)
{
	printk("hog init stat\n");
}

static uint8_t bt_bas_get_battery_level(void)
{
	return battery_level;
}

static int bt_bas_set_battery_level(uint8_t level)
{
	int rc;

	if (level > 100U) {
		return -EINVAL;
	}

	battery_level = level;

	rc = bt_gatt_notify(hids_conn, &hog_svc.attrs[12+15], &level, sizeof(level));
	return rc == -ENOTCONN ? 0 : rc;
}

static void bas_notify(struct k_work *work)
{
	battery_level = bt_bas_get_battery_level();

	if (battery_level <= 0 ) {
		battery_level = 100U;
	}
	battery_level-=10;

	
	bt_bas_set_battery_level(battery_level);
}

/**
 * F429		------    nrf52832	 -----	zephyr dts 
 * 
 * KEY1__PH2 -----> A9  -----> P26  ----> sw1
 * KEY0__PH3 -----> A8  -----> P27  ----> sw0
 * KEY2__PC13 ----> A3 	-----> P25  ----> sw2
*/
#define SW0_NODE DT_ALIAS(sw0)
#define SW1_NODE DT_ALIAS(sw1)
#define SW2_NODE DT_ALIAS(sw2)

const struct gpio_dt_spec sw0 = GPIO_DT_SPEC_GET(SW0_NODE, gpios);
const struct gpio_dt_spec sw1 = GPIO_DT_SPEC_GET(SW1_NODE, gpios);
const struct gpio_dt_spec sw2 = GPIO_DT_SPEC_GET(SW2_NODE, gpios);


static void hog_button_loop(struct k_work *work)
{
	int8_t report[3] = {0, 0, 0};
	gpio_pin_configure_dt(&sw0, GPIO_INPUT);
	gpio_pin_configure_dt(&sw1, GPIO_INPUT);
	gpio_pin_configure_dt(&sw2, GPIO_INPUT);

	k_work_schedule(&bas_work, K_MSEC(5000));//k_work_reschedule(reload cnt), k_work_schedule(no reload cnt).

	if (simulate_input)
	{
		/* HID Report:
			* Byte 0: buttons (lower 3 bits)
			* Byte 1: X axis (int8)
			* Byte 2: Y axis (int8)
			*/

		memset(report, 0, sizeof(report));

		if (gpio_pin_get_dt(&sw0)) {
				printk("sw0 down lift.\n");
				report[0] |= BIT(0);
		}
		if (gpio_pin_get_dt(&sw1)) {
				printk("sw1 down right.\n");
				report[0] |= BIT(1);
		}
	
		
		if(bt_gatt_notify(hids_conn, &hog_svc.attrs[5], report, sizeof(report)) < 0){
			printk("err notify\n");
		}
	}
}
static void hids_timer_handler(struct k_timer *timer)
{
	k_work_submit(&hog_button);
}

static int ble_state_init(void)
{
	k_timer_init(&hids_timer, hids_timer_handler, NULL);
	k_work_init(&hog_button, hog_button_loop);
	k_work_init_delayable(&state_work, ble_state_handler);
	k_work_init_delayable(&bas_work, bas_notify);
	ble_hid.set_state(BTHID_STATE_POWER_ON);//开机
	printk("ble_state_init \n");
	return 0;
}


SYS_INIT(ble_state_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);

const char *bthid_state_string(enum bthid_state state)
{
	switch (state) {
	case BTHID_STATE_UNINIT: return "Uninit";
	case BTHID_STATE_READY: return "Ready";
	case BTHID_STATE_POWER_OFF: return "Power off";
	case BTHID_STATE_POWER_ON: return "Power on";
	case BTHID_STATE_IDLE: return "Idle";
	case BTHID_STATE_DISCOVER: return "Discover";
	case BTHID_STATE_CONNECTING: return "Connecting";
	case BTHID_STATE_CONNECTED: return "Connected";
	case BTHID_STATE_ACTIVE: return "Active";
	case BTHID_STATE_MAX: return "MAX";
	}

	return "SB";
}

